-
Notifications
You must be signed in to change notification settings - Fork 163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
アウトライン解析ウィンドウのツリービューの設定処理の高速化 #1648
Conversation
CDlgFuncList::SetTree においてアイテムを追加するループの前後で WM_SETREDRAW メッセージを使用する事で描画の抑制 ソート種別が SORTTYPE_DEFAULT もしくは SORTTYPE_DEFAULT_DESC の場合は、ツリービューへのデータ追加方法を調整する事で CDlgFuncList::SortTree の呼び出しを行う必要が無くして高速化
✅ Build sakura 1.0.3713 completed (commit e20736c2b3 by @beru) |
Java専用のアウトライン表示コードが存在していて、そこに対策します。 アクションから画面表示までの間に行っている処理が「適切」なのであれば、 要望として「一部処理を省略してでも表示を速くしたい」はあるのかも知れません。 コードをざっと見た感じ、「処理順が不適切」という詳細設計的なバグに対処している雰囲気を感じます。
だとするならば、修正は「高速化したい」から行うべきなんではなくて、「詳細設計が不適切なのは改善すべき」だから行う感じになるような。 個人的には生のツリーハンドルをメソッド引数に採用するのがちょっと嫌です。 あとまぁ、「5秒近くかかる」をどうしても「問題」としたい場合、修正を適用したら何秒まで縮められるかを書くべきと思います。 |
その論の、処理が「適切」かどうかを誰がどう決めるのか良くわかりません…。 単純に待ち時間が長いのは嫌なので処理時間が短くなるようにしたいです。
今のところ「高速モード」を作る事は考えてません。 動作確認に 純粋に10万行でアウトライン解析に5秒掛かるのが速いのかそれとも遅いのかでいうと、処理内容をちゃんと見てませんが多分遅い部類だと思います。
上記の説明が「処理順が不適切」にどう繋がるのかよくわかりませんでした。 berryzplusさんもWindowsAPIを使うので当然分かっていると思いますが、ウィンドウハンドルの取得には殆ど時間は掛からない筈です。該当処理でウィンドウハンドルを取得する関数の呼び出し回数はそもそもそこまで多くないので。 自分がウィンドウハンドルを引数経由で渡すように変更したのは高速化の為ではないです。どちらかというとリファクタリング的な意味合いで変えました。
とりあえず大幅には変えずに少ない手間で高速化を行おうと考えてます。
ウィンドウハンドルを引数経由で渡すように変更したのは良くなかったですね。
体感では5秒ぐらいかかっていたのが2秒ぐらいになりました。 |
個人的には、アウトライン解析表示出しっぱなしのサクラエディタで teraterm のログファイル※ (数千行) をうっかり開いてしまった時のフリーズ時間が短縮されるのが嬉しいですね。 |
間違えて巨大なファイルを開いてしまってアウトライン解析に時間が掛かる場合はESCキー押しで中断が出来れば良いですね。 |
処理時間が半分以下になっていたので、どうしてこんなに速くなったのか興味本位で変更を一部戻したりなどして見てみたところ、WM_SETREDRAW を使ってアイテム追加中の再描画をやめた所がほとんどのようでした。 旧式なコントロールは描画が遅いということなんでしょうね。。 |
https://devblogs.microsoft.com/oldnewthing/20110124-00/?p=11683 の解説によると |
標準コントロールの ListView には VirtualMode がありますが TreeView にはないようなので大量のアイテムを扱うのは苦手っぽいですね。 フィルタリング表示は出来ないので、アウトライン解析で大量のアイテムが表示されても操作性が良くない気がします。 IDEのクラスビューのように管理している複数のソースコードのファイルのシンボル表示を行うとなると大量のアイテムを表示するので表示パフォーマンスに気を使う必要が出てきそうですね。 |
なるほど。 |
関数名
画面表示を行うために必要な処理であれば、どんなに時間がかかっても実施するのが筋だと思います。 ツリーハンドルを渡し忘れているために再取得が発生するのを対策しているように見えましたが、描画のためにツリーハンドルを「再取得すること」は「必要」なんでしょうか?
主観的なツッコミとしては、
ぼくのコード理解に誤りがありそうな気がしてきました。 が、ウインドウハンドル(hWnd)ではなくて、ツリーハンドルの話をしたつもりでした。 ・ルート という階層構造を処理するとき「アイテム10000_1」にアクセスするにはツリーハンドルが必要です。
これまでの経緯からすると、単純には「やめといたほうがいい」っすね 😃
2秒・・・・ やっぱり「仕様です。諦めてください」が妥当だと思います。 本当に「仕様」なのか、とか、「遅いんじゃヴォケ!」とかの感想も妥当だと思うので、どっかで対策すべきなのかな。 ある程度時間のかかる処理を「毎回やり直す」ことが、本当に仕様として必要なのか、とか。 |
さて、やり取りを読み返してみて、 高速化の効果を得られたのは だとすると、 であるなら「SetTreeJavaの変更は余計」ということになり、 |
勝手ながら私の方で SetData 関数の時間内訳の変化を見てみました。 PR説明に書かれている test_100k.txt を一度読み込ませた後、F11キーを2連打して再解析掛けた時のログになります。
「ソート処理があってもなくても変わらな」かったのは、その時に読み込ませていたデータに依るところがあったようでした。(誤解を招くことを書いてしまいすみません😔) |
試しに (ListView|TreeView)_DeleteAllItems の前後にも WM_SETREDRAW を追加したところ該当区間の処理時間が半減してしまいましたので、そういうことだったようです。。
|
Java以外の言語でも使うわけなので
処理を開始してから完了するまでの時間は世界最速のスパコンを使ってもブラックホールが蒸発するぐらい掛かります、とか言われたら首をしめてしまうと思います。
高速化の為に色々な対策は取れると思います。仕様やデータの持ち方や処理方式を変えたりとか。ただこのPRではそこまでやる事は考えていません。 |
そこでも大きく処理時間が掛かる事があるんですね。手抜きしてちゃんと処理時間の計測をしていなかったので気づきませんでした。
|
hwndList と hwndTree を非表示にするタイミングの変更 hwndList と hwndTree の描画を WM_SETREDRAW メッセージで抑える範囲を広げる 選択状態更新処理は最後に行うように変更(WM_SETREDRAWメッセージで描画を抑えている間は機能しない模様)
#1648 (comment) で @suconbu さんが、(ListView|TreeView)_DeleteAllItems の前後にも WM_SETREDRAW を追加すると処理時間が減るという事を教えてくれたので、WM_SETREDRAW メッセージの呼び出しを SetTree や SetTreeJava メソッド内で行うのではなく呼び出し元の SetData メソッドで行うようにして描画を抑える範囲を広げました。 あと別ブランチで
今回は3番の方法を使っています。1番は仕様変更になるし2番は実装が大変そうなので諦めます。 |
変更前の処理時間についても比較用に別ブランチを用意して計測しました。 測定条件は同じで
変更前後の処理時間を並べて比較しました。
再表示に掛かる処理時間がまだまだ大きくてレスポンスが悪いと思いますが、 |
✅ Build sakura 1.0.3717 completed (commit 206407bca1 by @beru) |
|
||
SetDocLineFuncList(); | ||
if( OUTLINE_C_CPP == m_nListType || OUTLINE_CPP == m_nListType ){ /* C++メソッドリスト */ | ||
m_nViewType = VIEWTYPE_TREE; | ||
SetTreeJava( GetHwnd(), TRUE ); // Jan. 04, 2002 genta Java Method Treeに統合 | ||
SetTreeJava( GetHwnd(), hInsertAfter, TRUE ); // Jan. 04, 2002 genta Java Method Treeに統合 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
結局、引数を増やすんです?
「引数を渡さないのは非効率なのは自明」だけど、実害は出てないと理解しました。
紛らわしいので引数追加はrevert(と同じになるようにコミットを積む)が良さそうに思います。
目下、自分が気にしているのはあとココだけです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
引数を増やさないで同じ処理を行うとなると下記の手段が考えられます。
CDlgFuncList
クラスにメンバー変数HTREEITEM m_hInsertAfter
を追加してそれ経由で情報を渡すSetTree
とSetTreeJava
でm_nSortType
の値を元にhInsertAfter
ローカル変数を初期化する記述を重複して書く
関連する実装について説明します。
hInsertAfter
引数は SetTree
や SetTreeJava
の中で呼び出す TreeView_InsertItem
マクロの第2引数に渡される TV_INSERTSTRUCT
構造体の hInsertAfter
メンバーに設定しています。
元の実装では SetTree
では TVI_FIRST
が TV_INSERTSTRUCT::hInsertAfter
に設定されていました。そして SetTreeJava
では TVI_LAST
が TV_INSERTSTRUCT::hInsertAfter
に設定されていました。
このPRの実装では m_nSortType
の値によって TVI_FIRST
と TVI_LAST
のどちらを設定するかを変える事で、後で SortTree
の呼び出しを省けようにしています。なお SortTree
の呼び出しを省いているのは順序が デフォルト
と デフォルト(降順)
の場合のみです。それらについてはツリービューへの追加順序を調整すれば後でソートしないでも問題ないだろうと判断しました。
https://docs.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tvinsertstructa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちょっと分からなかったのですが「PRの実現に必要な変更」なのであれば、そう言って貰えれば良いです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
どちらかというと必要な変更だと思ってます。こうする事で SortTree の呼び出しを省いて高速化できるので。
挙動から察するに、全削除の場合でも描画のための何かの処理が行われている、ということが言えそうです。 アプリ仕様的に、全削除直後の状態を表示する必要はないので、やっぱりそれも「無駄な処理」にあたるのではないかと思います。(該当の描画処理を抑制して高速化するのは、適切だと思います。) |
元の実装では このPRでは処理の冒頭でコントロールを非表示にはしないようにしました。コントロールを一時的に非表示にするより表示しっぱなしにしておいた方が画面の見た目の変化が自然になる為です。 なお |
SonarCloud Quality Gate failed. |
✅ Build sakura 1.0.3718 completed (commit a999ab9b34 by @beru) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちょっと全容が理解できていないですが、良さそうに思います。
レビューありがとうございます。マージします。 |
PR の目的
アウトライン解析ウィンドウのツリービューの表示を高速化するのが目的です。
動作確認には #1398 の説明に添付されている test.zip の中の
test_100k.txt
ファイルを使用しました。カテゴリ
PR の背景
test_100k.txt
ファイルを開いた後にF11キーを押してアウトライン解析を行うと、自分が今使っているPCだと表示されるまでに5秒近くかかる事が分かりました。処理時間が掛かりすぎだと思うので高速化しました。PR のメリット
アウトライン解析の表示が速くなります。
PR のデメリット (トレードオフとかあれば)
CDlgFuncList::SetTreeJava
とCDlgFuncList::SetTree
の引数を増やしたのでその分コードが少し読みづらくなったかもしれません。仕様・動作説明
アウトライン解析のツリービューにアイテムを追加する処理の前後で
WM_SETREDRAW
メッセージを呼ぶようにしました。表示順が「デフォルト」もしくは「デフォルト(降順)」の場合は、ツリービューにアイテムを追加する際にパラメータ
HTREEITEM::hInsertAfter
の値を調整する事で、後でソート処理(CDlgFuncList::SortTree)を呼ぶ必要が無くせるのではないかと考えました。ツリービューのソート処理は要素数が多いとその分だけ時間が掛かるので、呼び出しを省くことでその分の処理時間を減らしました。PR の影響範囲
アウトライン解析ウィンドウの表示処理
テスト内容
テスト1
手順
test_100k.txt
を開く関連 issue, PR
#1398